#include "server.h"
#include <jsoncpp/json/json.h>
#include <iostream>

GameServer::GameServer(int gameWidth, int gameHeight, int port) 
    : game_(gameWidth, gameHeight), webSocketService_(port), 
      running_(false), nextPlayerId_(1) {
    webSocketService_.setMessageHandler(
        std::bind(&GameServer::handleMessage, this, 
            std::placeholders::_1, std::placeholders::_2));
}

GameServer::~GameServer() {
    stop();
}

void GameServer::start() {
    running_ = true;
    gameThread_ = std::thread(&GameServer::gameLoop, this);
    webSocketService_.run();
}

void GameServer::stop() {
    running_ = false;
    if (gameThread_.joinable()) {
        gameThread_.join();
    }
    webSocketService_.stop();
}

void GameServer::gameLoop() {
    const int frameRate = 10; // 10 frames per second
    const std::chrono::milliseconds frameDuration(1000 / frameRate);
    
    while (running_) {
        auto start = std::chrono::steady_clock::now();
        
        game_.update();
        std::string gameState = game_.getGameState();
        webSocketService_.broadcast(gameState);
        
        auto end = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
        
        if (elapsed < frameDuration) {
            std::this_thread::sleep_for(frameDuration - elapsed);
        }
    }
}

void GameServer::handleMessage(websocketpp::connection_hdl hdl, const std::string& message) {
    Json::Value jsonMsg;
    Json::Reader reader;
    
    if (!reader.parse(message, jsonMsg)) {
        std::cerr << "Failed to parse message: " << message << std::endl;
        return;
    }
    
    auto con = webSocketService_.getServer().get_con_from_hdl(hdl);
    void* connPtr = con.get();
    
    std::string type = jsonMsg["type"].asString();
    
    if (type == "join") {
        // Assign a new player ID
        int playerId = nextPlayerId_++;
        playerConnections_[connPtr] = playerId;
        
        // Add player to game
        game_.addPlayer(playerId);
        
        // Send player their ID
        Json::Value response;
        response["type"] = "player_id";
        response["id"] = playerId;
        
        Json::StreamWriterBuilder builder;
        webSocketService_.send(hdl, Json::writeString(builder, response));
    } 
    else if (type == "direction") {
        auto it = playerConnections_.find(connPtr);
        if (it != playerConnections_.end()) {
            int playerId = it->second;
            std::string dirStr = jsonMsg["direction"].asString();
            
            Direction dir;
            if (dirStr == "up") dir = Direction::UP;
            else if (dirStr == "down") dir = Direction::DOWN;
            else if (dirStr == "left") dir = Direction::LEFT;
            else if (dirStr == "right") dir = Direction::RIGHT;
            else return;
            
            game_.changeDirection(playerId, dir);
        }
    } 
    else if (type == "leave") {
        auto it = playerConnections_.find(connPtr);
        if (it != playerConnections_.end()) {
            int playerId = it->second;
            game_.removePlayer(playerId);
            playerConnections_.erase(it);
        }
    }
}